home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 September / PCWorld_2008-09_cd.bin / v cisle / sadanastroju / lightning-0.8-tb-win.xpi / js / calMonthGridPrinter.js < prev    next >
Text File  |  2007-10-29  |  14KB  |  351 lines

  1. /* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  * ***** BEGIN LICENSE BLOCK *****
  3.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Mozilla Public License Version
  6.  * 1.1 (the "License"); you may not use this file except in compliance with
  7.  * the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/MPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is Mozilla Calendar code.
  16.  *
  17.  * The Initial Developer of the Original Code is
  18.  *   Joey Minta <jminta@gmail.com>
  19.  * Portions created by the Initial Developer are Copyright (C) 2006
  20.  * the Initial Developer. All Rights Reserved.
  21.  *
  22.  * Contributor(s):
  23.  *   Matthew Willis <mattwillis@gmail.com>
  24.  *
  25.  * Alternatively, the contents of this file may be used under the terms of
  26.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  27.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28.  * in which case the provisions of the GPL or the LGPL are applicable instead
  29.  * of those above. If you wish to allow use of your version of this file only
  30.  * under the terms of either the GPL or the LGPL, and not to allow others to
  31.  * use your version of this file under the terms of the MPL, indicate your
  32.  * decision by deleting the provisions above and replace them with the notice
  33.  * and other provisions required by the GPL or the LGPL. If you do not delete
  34.  * the provisions above, a recipient may use your version of this file under
  35.  * the terms of any one of the MPL, the GPL or the LGPL.
  36.  *
  37.  * ***** END LICENSE BLOCK ***** */
  38.  
  39. /**
  40.  * Prints a rough month-grid of events/tasks
  41.  */
  42.  
  43. function calMonthPrinter() {
  44.     this.wrappedJSObject = this;
  45. }
  46.  
  47. calMonthPrinter.prototype.QueryInterface =
  48. function QueryInterface(aIID) {
  49.     if (!aIID.equals(Components.interfaces.nsISupports) &&
  50.         !aIID.equals(Components.interfaces.calIPrintFormatter)) {
  51.         throw Components.results.NS_ERROR_NO_INTERFACE;
  52.     }
  53.  
  54.     return this;
  55. };
  56.  
  57. calMonthPrinter.prototype.getName =
  58. function monthPrint_getName() {
  59.     return calGetString("calendar", "monthPrinterName");
  60. };
  61. calMonthPrinter.prototype.__defineGetter__("name", calMonthPrinter.prototype.getName);
  62.  
  63. calMonthPrinter.prototype.formatToHtml =
  64. function monthPrint_format(aStream, aStart, aEnd, aCount, aItems, aTitle) {
  65.     var html = <html/>
  66.     html.appendChild(
  67.             <head>
  68.                 <title>{aTitle}</title>
  69.                 <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>
  70.                 <style type='text/css'/>
  71.             </head>);
  72.     html.head.style = ".main-table { font-size: 26px; font-weight: bold; }\n";
  73.     html.head.style += ".day-name { border: 1px solid black; background-color: #e0e0e0; font-size: 12px; font-weight: bold; }\n";
  74.     html.head.style += ".day-box { border: 1px solid black; vertical-align: top; }\n";
  75.     html.head.style += ".out-of-month { background-color: gray !important; }\n";
  76.     html.head.style += ".day-off { background-color: #D3D3D3 !important; }\n";
  77.  
  78.     // If aStart or aEnd weren't passed in, we need to calculate them based on
  79.     // aItems data.
  80.  
  81.     var start = aStart;
  82.     var end = aEnd;
  83.     if (!start || !end) {
  84.         for each (var item in aItems) {
  85.             var itemStart = item.startDate || item.entryDate;
  86.             var itemEnd = item.endDate || item.dueDate;
  87.             if (!start || (itemStart && start.compare(itemStart) == 1)) {
  88.                 start = itemStart;
  89.             }
  90.             if (!end || (itemEnd && end.compare(itemEnd) == -1)) {
  91.                 end = itemEnd;
  92.             }
  93.         }
  94.     }
  95.  
  96.     // Play around with aStart and aEnd to determine the minimal number of
  97.     // months we can show to still technically meet their requirements.  This
  98.     // is most useful when someone printed 'Current View' in the month view. If
  99.     // we take the aStart and aEnd literally, we'll print 3 months (because of
  100.     // the extra days at the start/end), but we should avoid that.
  101.     //
  102.     // Basically, we check whether aStart falls in the same week as the start
  103.     // of a month (ie aStart  is Jan 29, which often is in the same week as
  104.     // Feb 1), and similarly whether aEnd falls in the same week as the end of
  105.     // a month.
  106.     var weekStart = getPrefSafe("calendar.week.start", 0);
  107.     maybeNewStart = start.clone();
  108.     maybeNewStart.day = 1;
  109.     maybeNewStart.month = start.month+1;
  110.  
  111.     var date = start.clone();
  112.  
  113.     // First we have to adjust the end date for comparison, as the
  114.     // provided end date is exclusive, i.e. will not be displayed.
  115.  
  116.     var realEnd = end.clone();
  117.     realEnd.day -= 1;
  118.  
  119.     if (start.compare(realEnd) <= 0) {
  120.         // Only adjust dates if start date is earlier than end date.
  121.  
  122.         if ((start.month != realEnd.month) || (start.year != realEnd.year)) {
  123.             // We only need to adjust if start and end are in different months.
  124.  
  125.             // We want to check whether or not the start day is in the same
  126.             // week as the beginning of the next month. To do this, we take
  127.             // the start date, add seven days and subtract the "day of week"
  128.             // value (which has to be corrected in case we do not start on
  129.             // Sunday).
  130.             var testBegin = start.clone();
  131.             var startWeekday = testBegin.weekday;
  132.             if (startWeekday < weekStart) {
  133.                 startWeekday += 7;
  134.             }
  135.             testBegin.day += 7 + weekStart - startWeekday;
  136.             if (testBegin.compare(maybeNewStart) > 0) {
  137.                 start = maybeNewStart;
  138.                 date = start.clone();
  139.             }
  140.         }
  141.         if ((start.month != realEnd.month) || (start.year != realEnd.year)) {
  142.             // We only need to adjust if start and end are in different months.
  143.  
  144.             // Next, we want to check whether or not the end day is in the same
  145.             // week as the end of the previous month. So we have to get the
  146.             // "day of week" value for the end of the previous month, adjust it
  147.             // if necessary (when start of week is not Sunday) and check if the
  148.             // end day is in the same week.
  149.  
  150.             var lastDayOfPreviousMonth = end.clone();
  151.             lastDayOfPreviousMonth.day = 0;
  152.             var lastDayWeekday = lastDayOfPreviousMonth.weekday;
  153.             if (lastDayWeekday < weekStart) {
  154.                 lastDayWeekday += 7;
  155.             }
  156.             if (date.month != end.month) {
  157.                 date.day = 1;
  158.             }
  159.             if ((lastDayWeekday + end.day - 1) < (7 + weekStart)) {
  160.                 date.day = end.day;
  161.             }
  162.  
  163.             // Finally, we have to check whether we adjusted the dates too
  164.             // well so that nothing is printed. That happens if you print just
  165.             // one week which has the last day of a month in it.
  166.  
  167.             if (date.compare(end) >= 0) {
  168.                 date.day = 1;
  169.             }
  170.         } else {
  171.             date.day = 1;
  172.         }
  173.     } else {
  174.          // If start date is after end date, just print empty month.
  175.          date = realEnd.clone();
  176.     }
  177.  
  178.     var body = <body/>
  179.  
  180.     while (date.compare(end) < 0) {
  181.         var monthName = calGetString("dateFormat", "month." + (date.month +1)+ ".name");
  182.         monthName += " " + date.year;
  183.         body.appendChild(
  184.                      <table border='0' width='100%' class='main-table'>
  185.                          <tr> 
  186.                              <td align='center' valign='bottom'>{monthName}</td>
  187.                          </tr>
  188.                      </table>);
  189.         body.appendChild(this.getStringForMonth(date, aItems));
  190.         // Make sure each month gets put on its own page
  191.         body.appendChild(<br style="page-break-after:always;"/>);
  192.         date.month++;
  193.     }
  194.     html.appendChild(body);
  195.  
  196.     var convStream = Components.classes["@mozilla.org/intl/converter-output-stream;1"]
  197.                                .getService(Components.interfaces.nsIConverterOutputStream);
  198.     convStream.init(aStream, 'UTF-8', 0, 0x0000);
  199.     convStream.writeString(html.toXMLString());
  200. };
  201.  
  202. calMonthPrinter.prototype.getStringForMonth =
  203. function monthPrint_getHTML(aStart, aItems) {
  204.     var weekStart = getPrefSafe("calendar.week.start", 0);
  205.  
  206.     var monthTable = <table style='border:1px solid black;' width='100%'/>
  207.     var dayNameRow = <tr/>
  208.     for (var i = 0; i < 7; i++) {
  209.         var dayName = calGetString("dateFormat", "day."+ (((weekStart+i)%7)+1) + ".Mmm");
  210.         dayNameRow.appendChild(<td class='day-name' align='center'>{dayName}</td>);
  211.     }
  212.     monthTable.appendChild(dayNameRow);
  213.  
  214.     // Set up the item-list so it's easy to work with.
  215.     function hasUsableDate(item) {
  216.         return item.startDate || item.entryDate || item.dueDate;
  217.     }
  218.     var filteredItems = aItems.filter(hasUsableDate);
  219.  
  220.     var calIEvent = Components.interfaces.calIEvent;
  221.     var calITodo = Components.interfaces.calITodo
  222.     function compareItems(a, b) {
  223.         // Sort tasks before events
  224.         if (a instanceof calIEvent && b instanceof calITodo) {
  225.             return 1;
  226.         }
  227.         if (a instanceof calITodo && b instanceof calIEvent) {
  228.             return -1;
  229.         }
  230.         if (a instanceof calIEvent) {
  231.             var startCompare = a.startDate.compare(b.startDate);
  232.             if (startCompare != 0) {
  233.                 return startCompare;
  234.             }
  235.             return a.endDate.compare(b.endDate);
  236.         }
  237.         var aDate = a.entryDate || a.dueDate;
  238.         var bDate = b.entryDate || b.dueDate;
  239.         return aDate.compare(bDate);
  240.     }
  241.     var sortedList = filteredItems.sort(compareItems);
  242.     var firstDate = aStart.startOfMonth.startOfWeek.clone();
  243.     firstDate.day += weekStart;
  244.     if (aStart.startOfMonth.weekday < weekStart) {
  245.         // Go back one week to make sure we display this day
  246.         firstDate.day -= 7;
  247.     }
  248.  
  249.     var lastDate = aStart.endOfMonth.endOfWeek.clone();
  250.     if (aStart.endOfMonth.weekday < weekStart) {
  251.         // Go back one week so we don't display any extra days
  252.         lastDate.day -= 7;
  253.     }
  254.     firstDate.isDate = true;
  255.     lastDate.isDate = true;
  256.  
  257.     var date = firstDate.clone();
  258.     var itemListIndex = 0;
  259.     while (date.compare(lastDate) != 1) {
  260.         monthTable.appendChild(this.makeHTMLWeek(date, sortedList, aStart.month));
  261.     }
  262.     return monthTable;
  263. };
  264.  
  265. calMonthPrinter.prototype.makeHTMLWeek =
  266. function makeHTMLWeek(date, sortedList, targetMonth) {
  267.     var weekRow = <tr/>;
  268.     const weekPrefix = "calendar.week.";
  269.     var prefNames = ["d0sundaysoff", "d1mondaysoff", "d2tuesdaysoff",
  270.                      "d3wednesdaysoff", "d4thursdaysoff", "d5fridaysoff", "d6saturdaysoff"];
  271.     var defaults = [true, false, false, false, false, false, true];
  272.     var daysOff = new Array();
  273.     for (var i in prefNames) {
  274.         if (getPrefSafe(weekPrefix+prefNames[i], defaults[i])) {
  275.             daysOff.push(Number(i));
  276.         }
  277.     }
  278.  
  279.     for (var i = 0; i < 7; i++) {
  280.         var myClass = 'day-box';
  281.         if (date.month != targetMonth) {
  282.             myClass += ' out-of-month';
  283.         } else if (daysOff.some(function(a) { return a == date.weekday; })) {
  284.             myClass += ' day-off';
  285.         }
  286.         var day = <td align='left' valign='top' class={myClass} height='100' width='100'/>
  287.         var innerTable = <table valign='top' style='font-size: 10px;'/>
  288.         var dateLabel = <tr valign='top'>
  289.                             <td valign='top' align='left'>{date.day}</td>
  290.                         </tr>
  291.         innerTable.appendChild(dateLabel);
  292.         var defaultTimezone = calendarDefaultTimezone();
  293.         for each (var item in sortedList) {
  294.             var sDate = item.startDate || item.entryDate || item.dueDate;
  295.             var eDate = item.endDate || item.dueDate || item.entryDate;
  296.             if (sDate) {
  297.                 sDate = sDate.getInTimezone(defaultTimezone);
  298.             }
  299.             if (eDate) {
  300.                 eDate = eDate.getInTimezone(defaultTimezone);
  301.             }
  302.  
  303.             // end dates are exclusive
  304.             if (sDate.isDate) {
  305.                 eDate = eDate.clone();
  306.                 eDate.day -= 1;
  307.             }
  308.             if (!eDate || eDate.compare(date) == -1) {
  309.                 continue;
  310.             }
  311.             itemListIndex = i;
  312.             if (!sDate || sDate.compare(date) == 1) {
  313.                 break;
  314.             }
  315.             var dateFormatter = 
  316.                     Components.classes["@mozilla.org/calendar/datetime-formatter;1"]
  317.                               .getService(Components.interfaces.calIDateTimeFormatter);
  318.             var time = "";
  319.             if (!sDate.isDate) {
  320.                 time = dateFormatter.formatTime(sDate);
  321.             }
  322.  
  323.             var calColor = item.calendar.getProperty('color');
  324.             if (!calColor) {
  325.                 calColor = "#A8C2E1";
  326.             }
  327.             var pb2 = Components.classes["@mozilla.org/preferences-service;1"]
  328.                                 .getService(Components.interfaces.nsIPrefBranch2);
  329.             var catColor;
  330.             try {
  331.                 catColor = pb2.getCharPref("calendar.category.color."+item.getProperty("CATEGORIES").toLowerCase());
  332.             } catch(ex) {}
  333.  
  334.             var style = 'font-size: 11px; text-align: left;';
  335.             style += ' background-color: ' + calColor + ';';
  336.             style += ' color: ' + getContrastingTextColor(calColor);
  337.             if (catColor) {
  338.                 style += ' border: solid ' + catColor + ' 2px;';
  339.             }
  340.             var item = <tr>
  341.                            <td valign='top' style={style}>{time} {item.title}</td>
  342.                        </tr>;
  343.             innerTable.appendChild(item);
  344.         }
  345.         day.appendChild(innerTable);
  346.         weekRow.appendChild(day);
  347.         date.day++;
  348.     }
  349.     return weekRow;
  350. };
  351.